﻿using System;
using System.IO;
using System.Xml;
using System.Text;
using System.CodeDom.Compiler;

using Weazel.Gezel.Model;

using GezelModel = Weazel.Gezel.Model.Model;

namespace Weazel.Gezel.Exporter
{
  public class ModelExporter
  {
    #region xml export

    /// <summary>
    /// Converts the gezel model to an xml representation which
    /// is returned as a string.
    /// </summary>
    /// <param name="model">the model to convert</param>
    /// <returns>xml description of model as a string</returns>
    public static string ToXmlString(GezelModel model)
    {
      // to hold the result
      StringBuilder stringBuffer = new StringBuilder();

      // get xml document
      XmlDocument doc = ToXmlDocument(model);

      // control how xml gets formatted
      XmlWriterSettings xmlWriterSettings = new XmlWriterSettings();
      xmlWriterSettings.Indent = true;
      xmlWriterSettings.IndentChars = "  ";
      xmlWriterSettings.ConformanceLevel = ConformanceLevel.Document;
      xmlWriterSettings.NewLineHandling = NewLineHandling.Entitize;

      // write xml to stringbuffer
      XmlWriter xmlWriter = XmlWriter.Create(stringBuffer, xmlWriterSettings);

      doc.WriteTo(xmlWriter);
      xmlWriter.Flush();

      // convert to immutable string
      return stringBuffer.ToString();
    }

    /// <summary>
    /// Converts the gezel model to an xml representation which
    /// is returned as an XmlDocument.
    /// </summary>
    /// <param name="model">the model to convert</param>
    /// <returns>xml description of model as an XmlDocument</returns>
    public static XmlDocument ToXmlDocument(GezelModel model)
    {
      // to hold the result
      XmlDocument xmlDocument = new XmlDocument();

      // root element of the xml description
      XmlElement modelElement = xmlDocument.CreateElement("Model");
      xmlDocument.AppendChild(modelElement);

      XmlComment datapathsComment = xmlDocument.CreateComment("datapaths");
      modelElement.AppendChild(datapathsComment);

      foreach (Datapath datapath in model.Datapaths.Values)
      {
        DatapathExporter.ToXml(xmlDocument, modelElement, datapath);
      }

			foreach (IPBlock ipBlock in model.IPBlocks.Values)
			{
				IpBlockExporter.ToXml(xmlDocument, modelElement, ipBlock);
			}

      XmlComment controllersComment = xmlDocument.CreateComment("controllers");
      modelElement.AppendChild(controllersComment);

      foreach (Controller controller in model.Controllers.Values)
      {
        ControllerExporter.ToXml(xmlDocument, modelElement, controller);
      }

      XmlComment systemsComment = xmlDocument.CreateComment("systems");
      modelElement.AppendChild(systemsComment);

      foreach (system system in model.Systems.Values)
      {
        SystemExporter.ToXml(xmlDocument, modelElement, system);
      }

      return xmlDocument;
    }

    #endregion

    #region gezel export

    public static string ToGezelString(GezelModel model)
    {
      StringWriter stringWriter = new StringWriter();
      IndentedTextWriter textWriter = new IndentedTextWriter(stringWriter);

			// output datapath/controller pairs next to each other
      foreach (Controller controller in model.Controllers.Values)
      {
				DatapathExporter.ToGezel(textWriter, controller.Datapath);
        ControllerExporter.ToGezel(textWriter, controller);
      }

			foreach (IPBlock ipBlock in model.IPBlocks.Values)
			{
				IpBlockExporter.ToGezel(textWriter, ipBlock);
			}

      foreach (system system in model.Systems.Values)
      {
        SystemExporter.ToGezel(textWriter, system);
      }

      return stringWriter.ToString();
    }

    #endregion
  }
}
